package com.yance.fim.handler;

import com.yance.fim.core.enums.Code;
import com.yance.fim.core.packets.FimPacket;
import com.yance.fim.core.enums.Command;
import com.yance.fim.core.packets.ack.ConnectAckPacket;
import com.yance.fim.core.packets.dto.ConnectRequest;
import com.yance.fim.utils.Constants;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.tio.core.ChannelContext;
import org.tio.core.Tio;
import org.tio.utils.json.Json;

import static com.yance.fim.core.enums.Code.*;

/**
 * 连接处理中心
 * 主要Websocket连接和Websocket断开连接处理
 *
 * @author yance
 */
@Service
public class ConnectorHandler implements BaseMessageHandler {

    private static final Logger logger = LoggerFactory.getLogger(ConnectorHandler.class);

    @Override
    public void handler(FimPacket fimPacket, ChannelContext channelContext) {
        Command command = fimPacket.getHeader().getCommand();
        switch (command) {
            case CONNECT:
                connectHandler(fimPacket, channelContext);
                break;
            case DISCONNECT:
                disconnectHandler(channelContext);
                break;
            default:
                logger.error("Unkonwn Command:{}", command);
                errorCommand(channelContext);
                break;
        }
    }

    /**
     * 处理未知指令，关闭当前连接
     *
     * @param channelContext
     */
    private void errorCommand(ChannelContext channelContext) {
        Tio.close(channelContext, "Unkonwn Command");
    }

    /**
     * 处理客户端主动断开连接命令
     *
     * @param channelContext
     */
    private void disconnectHandler(ChannelContext channelContext) {
        String clientId = (String) channelContext.getAttribute(Constants.ATTR_CLIENTID);
        String userAccount = (String) channelContext.getAttribute(Constants.ATTR_USERACCOUNT);
        if (StringUtils.isBlank(clientId)) {
            logger.error("Error clientId not exist");
            Tio.close(channelContext, "Error clientId not exist");
            return;
        }
        if (StringUtils.isBlank(userAccount)) {
            logger.error("Error userAccount not exist");
            Tio.close(channelContext, "Error userAccount not exist");
            return;
        }
        Tio.close(channelContext, "disconnect clientID:" + clientId);
        logger.warn("clientId = {} DISCONNECT", clientId);
    }

    /**
     * 处理客户端连接命令
     *
     * @param fimPacket
     * @param channelContext
     */
    private void connectHandler(FimPacket fimPacket, ChannelContext channelContext) {
        ConnectAckPacket connectAckPacket = new ConnectAckPacket();
        try {
            ConnectRequest connectRequest = Json.toBean(new String(fimPacket.getBody()), ConnectRequest.class);
            String clientId = connectRequest.getClientId();
            String userAccount = connectRequest.getUserAccount();
            logger.info("handle ConnectRequest. clientId={}, userAccount={}", clientId, userAccount);
            //自定义协议检验
            if (!fimPacket.getHeader().isValid()) {
                connectAckPacket.setCode(CONNECTION_REFUSED_UNACCEPTABLE_PROTOCOL);
                logger.error(" protocol is not valid. clientId={}", clientId);
                Tio.send(channelContext, connectAckPacket);
                Tio.close(channelContext, "protocol is not valid");
                return;
            }
            //用户账号、客户端ID参数校验
            if (StringUtils.isBlank(clientId)) {
                logger.error("handle ConnectRequest clientId is empty");
                connectAckPacket.setCode(CONNECT_REFUSE_CLIENTID_IS_EMPTY);
                Tio.send(channelContext, connectAckPacket);
                Tio.close(channelContext, "protocol version is not valid");
                return;
            }
            if (StringUtils.isBlank(clientId)) {
                logger.error("handle ConnectRequest userAccount is empty");
                connectAckPacket.setCode(CONNECT_REFUSE_USERACCOUNT_IS_EMPTY);
                Tio.send(channelContext, connectAckPacket);
                Tio.close(channelContext, "protocol version is not valid");
                return;
            }
            //TODO: 登录验证

            //TODO: 用户Session处理

            Tio.bindBsId(channelContext, clientId);
            channelContext.setAttribute(Constants.ATTR_USERACCOUNT, userAccount);
            channelContext.setAttribute(Constants.ATTR_CLIENTID, clientId);
            logger.info("The ConnectRequest has been handled. clientId = {}, userAccount = {}", clientId, userAccount);
            //连接成功,回复客户端Ack
            sendConnectAck(channelContext, connectAckPacket, connectRequest);
        } catch (Exception e) {
            e.printStackTrace();
            connectAckPacket.setCode(CONNECT__REFUSE_SYSTEM_ERROR);
            Tio.send(channelContext, connectAckPacket);
            Tio.close(channelContext, "System error");
        }
    }

    /**
     * 连接成功,回复Ack,通知客户端，可以进行下一步的命令操作
     *
     * @param channelContext
     * @param connectAckPacket
     * @param connectRequest
     */
    private void sendConnectAck(ChannelContext channelContext, ConnectAckPacket connectAckPacket, ConnectRequest connectRequest) {
        connectAckPacket.setCode(Code.CONNECTION_ACCEPTED);
        //TODO:初始化数据等
        connectAckPacket.setBody("Hello FIM".getBytes());
        Tio.send(channelContext, connectAckPacket);
    }
}
